package io.gitee.macxiang.utils;

import java.security.MessageDigest;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class Crypt {

  /**获取Aes密钥
   * @param key 要加密的字符串
   * @return 具有时间限制的密钥;每分钟返回值都会变动一次,用于伪RSA;
   */
  static private SecretKey getAesSecretKey(String key) {
    try {
      MessageDigest md = MessageDigest.getInstance("SHA-1");
      md.update(key.getBytes());
      byte[] data = md.digest(); // 获取秘钥哈希值

      byte[] salt = utils.getBytes(utils.timestampMinute()); // 根据时间戳的分钟取盐值
      md.update(salt);
      salt = md.digest(); // 得到时间戳与秘钥联合的哈希 作为正式盐值; 

      PBEKeySpec spec = new PBEKeySpec(
          Base64.getEncoder().encodeToString(data).toCharArray(), salt,
          65_536, // 延迟暴力破解
          256 // AES-256
      );
      // 使用 PBKDF2 从密码和盐生成密钥
      SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
      SecretKey tmp = factory.generateSecret(spec);
      // 转换为 AES 密钥
      SecretKey secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
      return secretKey;
    } catch (Exception e) {
    }
    return null;
  }

  /**AES分钟加密;每分钟变动一次密文;
   * @param bytes 要加密的字节数组
   * @param key   密钥;通常传入token等随机字串
   * @return      加密后的base64字符串; 同样的加密数据,返回密文每分钟变动一次;
   */
  static public String AesMinuteEncrypt(byte[] bytes, String key) {
    SecretKey secretKey = getAesSecretKey(key);

    try {
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
      cipher.init(Cipher.ENCRYPT_MODE, secretKey);
      return Base64.getEncoder().encodeToString(cipher.doFinal(bytes));
    } catch (Exception e) {
    }
    return null;
  }

  /**AES分钟解密;
   * @param str   要解密的字符串;加密后的密文需要在一分钟内才能解密;
   * @param key   密钥;通常传入token等随机字串
   * @return      解密后的字节数组;
   */
  static public byte[] AesMinuteDecrypt(String str, String key) {
    SecretKey secretKey = getAesSecretKey(key);
    try {
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
      cipher.init(Cipher.DECRYPT_MODE, secretKey);
      return cipher.doFinal(Base64.getDecoder().decode(str));
    } catch (Exception e) {
    }
    return null;
  }

}
